package project;

import java.util.ArrayList;

import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;
/**
 * la classe principale de l'etape b 
 * 
 * */
public class Etape_1_b {
	// numbre de applications pour chaque store
	public static int i = 1;
	// matrix de store
	public static KVStore[] stores;

	// initialisation de configuration
	public static void init() {
		String[] storeNames = new String[Init_1_b.N];
		storeNames[0] = "kvstore";
		storeNames[1] = "kvstore";
		String[] hostNames = new String[Init_1_b.N];
		hostNames[0] = "ari-31-312-14";
		hostNames[1] = "ari-31-312-15";
		String[] hostPorts = new String[Init_1_b.N];
		hostPorts[0] = "5000";
		hostPorts[1] = "5000";

		stores = new KVStore[Init_1_b.N];
		for (int i = 0; i < Init_1_b.N; i++) {
			stores[i] = KVStoreFactory.getStore(new KVStoreConfig(
					storeNames[i], hostNames[i] + ":" + hostPorts[i]));
		}
	}

	/**
	 * 
	 * */
	public static void main(String[] args) {

		init();

		// creer un vecteur contenu les cles a1-ai qui sont dans K1
		ArrayList<Integer> K1 = new ArrayList<Integer>();
		// creer un vecteur contenu les cles b1-bi qui sont dans K2
		ArrayList<Integer> K2 = new ArrayList<Integer>();
		// choisir aleatoire les cles a1-ai qui sont dans K1
		for (int m = 1; m <= i; m++) {
			Integer ai = (int) (Math.random() * Init_1_b.storeSize);
			if (!K1.contains(ai))
				K1.add(ai);
			else {
				m--;
				continue;
			}
		}
		// choisir aleatoire les cles a1-ai qui sont dans K2
		for (int m = 1; m <= i; m++) {
			Integer bi = (int) (Init_1_b.storeSize + Math.random() * Init_1_b.storeSize);
			if (!K2.contains(bi))
				K2.add(bi);
			else {
				m--;
				continue;
			}
		}

		// Creer 10 application A(ai) et A(bi)
		Application[] applications_s1 = new Application[i];
		Application[] applications_s2 = new Application[i];

		// Initialiser A(ai)
		for (int m = 1; m <= i; m++) {
			// manipule le produit K1.get(m - 1)
			applications_s1[m - 1] = new Application(stores, K1.get(m - 1));
		}
		// Initialiser A(bi)
		for (int m = 1; m <= i; m++) {
			// manipule le produit K2.get(m - 1)
			applications_s2[m - 1] = new Application(stores, K2.get(m - 1));
		}
		// Appeler simultanement A(ai) et A(bi)
		for (int m = 1; m <= i; m++) {
			// lancer l'application m-1
			applications_s1[m - 1].start();

		}
		for (int m = 1; m <= i; m++) {
			// lancer l'application m-1
			applications_s2[m - 1].start();
		}

		System.out.println("Average Time for S1: "
				+ getAverageTime(applications_s1) + "ms");
		System.out.println("Average Time for S2: "
				+ getAverageTime(applications_s2) + "ms");
	}
	/**
	 * Obtenir le temps moyenne d'execution pour C applications
	 * 
	 * @param applications
	 *            la vecteur d'application
	 * @return le temps moyenne d'execution
	 * */
	public static long getAverageTime(Application[] applications) {
		// verifier que les threads sont fini ou pas.
		boolean isFinished = true;
		do {
			isFinished = true;
			// iterer dans C applications
			for (int m = 1; m <= i; m++) {
				if (applications[m - 1].getState() != Thread.State.TERMINATED) {
					isFinished = false;
					break;
				}
			}
		} while (!isFinished);

		// calculer le temps total
		long waitTimeTotal = 0;
		for (int m = 1; m <= i; m++) {
			// ajouter le temps d'execution de application i-1
			waitTimeTotal += applications[m - 1].getWaitTime();
		}
		// calculer le temps moyenne
		return waitTimeTotal / i;
	}
}
